﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscoveryLogic.Common.Numeric
{
    /// <summary> Quick medium quality uniform pseudo-random number generator.
    /// 
    /// Produces uniformly distributed <tt>int</tt>'s and <tt>long</tt>'s in the closed intervals <tt>[Integer.MIN_VALUE,Integer.MAX_VALUE]</tt> and <tt>[Long.MIN_VALUE,Long.MAX_VALUE]</tt>, respectively, 
    /// as well as <tt>float</tt>'s and <tt>double</tt>'s in the open unit intervals <tt>(0.0f,1.0f)</tt> and <tt>(0.0,1.0)</tt>, respectively.
    /// <p>
    /// The seed can be any integer satisfying <tt>0 &lt; 4*seed+1 &lt; 2<sup>32</sup></tt>.
    /// In other words, there must hold <tt>seed &gt;= 0 && seed &lt; 1073741823</tt>.
    /// <p>
    /// <b>Quality:</b> This generator follows the multiplicative congruential method of the form                    
    /// <dt>
    /// <tt>z(i+1) = a * z(i) (mod m)</tt> with
    /// <tt>a=663608941 (=0X278DDE6DL), m=2<sup>32</sup></tt>.
    /// <dt>
    /// <tt>z(i)</tt> assumes all different values <tt>0 &lt; 4*seed+1 &lt; m</tt> during a full period of 2<sup>30</sup>.
    /// 
    /// <p>
    /// <b>Performance:</b> TO_DO
    /// <p>
    /// <b>Implementation:</b> TO_DO
    /// <p>
    /// Note that this implementation is <b>not synchronized</b>.                                  
    /// <p>
    /// 
    /// </summary>
    [Serializable]
    public class DRand : RandomEngine
    {
        /// <summary> Sets the receiver's seed. 
        /// This method resets the receiver's entire internal state.
        /// The following condition must hold: <tt>seed &gt;= 0 && seed &lt; (2<sup>32</sup>-1) / 4</tt>.
        /// </summary>
        /// <param name="seed">if the above condition does not hold, a modified seed that meets the condition is silently substituted.
        /// </param>
        virtual protected internal int Seed
        {
            set
            {
                if (value < 0)
                    value = -value;
                //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                int limit = (int)((System.Math.Pow(2, 32) - 1) / 4); // --> 536870911
                if (value >= limit)
                    value = value >> 3;

                this.current = 4 * value + 1;
            }

        }
        private int current;
        public const int DEFAULT_SEED = 1;
        /// <summary> Constructs and returns a random number generator with a default seed, which is a <b>constant</b>.</summary>
        public DRand()
            : this(DEFAULT_SEED)
        {
        }
        /// <summary> Constructs and returns a random number generator with the given seed.</summary>
        /// <param name="seed">should not be 0, in such a case <tt>DRand.DEFAULT_SEED</tt> is substituted.
        /// </param>
        public DRand(int seed)
        {
            Seed = seed;
        }
        /// <summary> Constructs and returns a random number generator seeded with the given date.
        /// 
        /// </summary>
        /// <param name="d">typically <tt>new java.util.Date()</tt>
        /// </param>
        //UPGRADE_TODO: Method 'java.util.Date.getTime' was converted to 'System.DateTime.Ticks' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilDategetTime'"
        //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
        public DRand(ref System.DateTime d)
            : this((int)d.Ticks)
        {
        }
        /// <summary> Returns a 32 bit uniformly distributed random number in the closed interval <tt>[Integer.MIN_VALUE,Integer.MAX_VALUE]</tt> (including <tt>Integer.MIN_VALUE</tt> and <tt>Integer.MAX_VALUE</tt>).</summary>
        public override int nextInt()
        {
            current *= 0x278DDE6D; /* z(i+1)=a*z(i) (mod 2**32) */
            // a == 0x278DDE6D == 663608941

            return current;
        }
    }
}
